package com.fly.visit.service;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.reactive.function.client.WebClient;

import com.fly.core.util.JsonBeanUtils;
import com.fly.visit.entity.Article;
import com.fly.visit.entity.BlogData;
import com.fly.visit.entity.Record;
import com.fly.visit.service.init.DataInitor;

import lombok.extern.slf4j.Slf4j;

/***
 * web访问服务
 */
@Slf4j
@Service
public class WebVisitorSevice
{
    @Autowired
    WebClient webClient;
    
    // 保存上次访问id
    long lastId;
    
    List<Article> articles = new ArrayList<>();
    
    @Autowired
    List<DataInitor> dataInitors;
    
    /**
     * 通过web接口提交
     * 
     * @param articles
     */
    public void setArticles(List<Article> articles)
    {
        this.articles = articles.stream().collect(Collectors.toList());
        log.info("############## articles.size: {} ", articles.size());
    }
    
    public List<Article> getArticles()
    {
        return articles;
    }
    
    @PostConstruct
    private void init()
    {
        try
        {
            initArticles();
            log.info("############## articles.size: {} ", articles.size());
            if (CollectionUtils.isEmpty(articles))
            {
                throw new RuntimeException("请先正确设置articles信息");
            }
            if (ResourceUtils.isJarURL(new ClassPathResource("").getURL()))
            {
                log.info("will execute saveJsonData......");
                BlogData blogData = new BlogData().setData(new Record().setList(articles));
                FileUtils.writeStringToFile(new File("/data/data-all.json"), JsonBeanUtils.beanToJson(blogData, true), Charset.defaultCharset(), false);
            }
        }
        catch (IOException e)
        {
            log.error(e.getMessage(), e);
        }
    }
    
    /**
     * 后台访问
     * 
     * @throws IOException
     * 
     */
    public void backVisit()
        throws IOException
    {
        // 随机选择多条，对viewCount较小的执行访问
        Article visit = new Random().ints(3, 0, articles.size()).mapToObj(index -> articles.get(index)).min(Comparator.comparing(Article::getViewCount)).get();
        if (visit.getArticleId() != lastId)
        {
            // 容器内需安装curl
            // CmdExecutor.execute("curl " + url, false);
            webClient.get().uri(visit.getUrl()).retrieve().bodyToMono(String.class).subscribe(response -> processVisited(visit, response), e -> log.error("process error: {}, {}", visit.getArticleId(), e.getMessage()));
            lastId = visit.getArticleId();
        }
        else
        {
            log.info("web visit ignore: {} --------", visit.getArticleId());
        }
    }
    
    /**
     * 处理访问成功记录
     * 
     * @param visit
     * @param response
     */
    private void processVisited(Article visit, String response)
    {
        log.info("process complted: {} ✈{} ==> {}", visit.getArticleId(), StringUtils.leftPad(visit.getViewCount().toString(), 5), visit.getTitle());
        // 800、2.8k、3k、1.9w、4w、10w+
        Long viewCount;
        String readCount = StringUtils.substringBetween(response, "阅读量", "</span>");
        Float num = NumberUtils.toFloat(readCount.replaceAll("k|w|\\+", ""));
        if (readCount.contains("k"))
        {
            viewCount = (long)(num * 1000.0F);
        }
        else if (readCount.contains("w"))
        {
            viewCount = (long)(num * 10000.0F);
        }
        else
        {
            viewCount = NumberUtils.toLong(readCount);
        }
        visit.setViewCount(viewCount);
    }
    
    /**
     * 初始化articles
     * 
     * @return
     * @throws IOException
     */
    private void initArticles()
    {
        // 串行流,有一个DataInitor执行init成功就返回
        dataInitors.stream()
            .peek(d -> log.info("{}", d.getClass().getName())) // debug
            .anyMatch(d -> d.init(articles));
    }
}
